using System;
using System.Runtime.Serialization;
using Picnic.Spec.Utils;

namespace Picnic.Spec.Exceptions
{
	/// <summary>
	/// Represents an exception which should be thrown when required and actual values are not equals.
	/// </summary>
	public class EqualsException : StatementException
	{
		private readonly object _requiredValue;
		private readonly object _actualValue;

		public EqualsException(object requiredValue, object actualValue)
			: base(CreateMessage(requiredValue, actualValue))
		{
			_requiredValue = requiredValue;
			_actualValue = actualValue;
		}

		/// <summary>
		/// Gets a required value.
		/// </summary>
		public object RequiredValue
		{
			get { return _requiredValue; }
		}

		/// <summary>
		/// Gets an actual value.
		/// </summary>
		public object ActualValue
		{
			get { return _actualValue; }
		}

		private static string CreateMessage(object requiredValue, object actualValue)
		{
			return string.Format(
				"Required and actual values are not equals [Required: {0}, Actual: {1}].",
				FormatValue.AsString(requiredValue),
				FormatValue.AsString(actualValue));
		}

		#region Default exception constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="EqualsException"/> class.
		/// </summary>
		public EqualsException()
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="EqualsException"/> class with a specified error message.
		/// </summary>
		/// <param name="message">The message that describes the error. </param>
		public EqualsException(string message)
			: base(message)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="EqualsException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
		/// </summary>
		/// <param name="message">The error message that explains the reason for the exception. </param><param name="innerException">The exception that is the cause of the current exception, or a <see langword="null"/> reference (Nothing in Visual Basic) if no inner exception is specified. </param>
		public EqualsException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="EqualsException"/> class with serialized data.
		/// </summary>
		/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data about the exception being thrown. </param><param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination. </param><exception cref="T:System.ArgumentNullException">The <paramref name="info"/> parameter is <see langword="null"/>. </exception><exception cref="T:System.Runtime.Serialization.SerializationException">The class name is <see langword="null"/> or <see cref="P:System.Exception.HResult"/> is zero (0). </exception>
		protected EqualsException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		#endregion
	}
}